package scala.Functional.ScalaList

import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.TreeSet
import scala.collection.immutable.TreeSet
import scala.collection.mutable.Map

object MainOB {
    def main(args: Array[String]): Unit = {

        val c = List(5, 4, 67, 8, 45, 7, 90, 21, 34, 65, 23, 6, 24, 29, 81, 1)
        val rs: List[Int] = iSort(c)
        printL(rs)

        val l1 = List(1, 2)
        val l2 = List(11, 22)
        val l3 = List(33, 44)

        val l_1 = l2 ::: (l1 ::: l3)
        printL(l_1)

        val l_2 = appendList(l1, l2)
        printL(l_2)

        val cc = endElemList(l_1)

        cc match {
            case Some(x) => println(x)
            case _       =>
        }

        println("\n---")

        val a1 = List('a', 'b', 'c')
        val a2 = List(1, 2, 3)
        val a3 = append1(a1, a2)
        println(a3)

        //higher-order method on class List
        val b1 = List(1, 2, 3)
        val b1_1 = b1.map(_ + 1)
        printL(b1_1)

        val c1 = List("The", "Quick", "Browse", "Fox")
        val c2 = c1.map(_.length())
        printL(c2)

        val c3 = c1.map(_.toList.reverse.mkString)
        printL(c3)

        val c4 = c1.mkString("{", "-", "}")
        println(c4)

        val d1 = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
        var sum = 0
        d1 foreach (sum += _)
        println("sum : " + sum)

        val d2 = d1.filter(_ % 2 == 1)
        printL(d2)
        val d3 = c1.filter(_.length() == 3)
        printL(d3)

        //List Buffer 
        val e1 = new ListBuffer[Int]
        e1 += 1
        e1 += 2
        3 +: e1
        e1 foreach (l => print(l + " "))
        println("\n-----\n")
        val e2 = e1.toList
        printL(e2)

        //array buffer
        val f1 = new ArrayBuffer[Int]()
        f1 += 4
        f1 += 5
        f1 foreach (l => print(l + " "))
        println("\nLast Element : " + f1.last)
        println("\n\n")

        println(countWords("See Spot run! Run, Spot. Run!")) //filter factor flattern

        val t1 = scala.collection.immutable.TreeSet(2, 3, 7, 4, 6, 8)
        println(t1)

        val t2 = scala.collection.mutable.TreeSet(2, 3, 4, 7, 5, 9, 1)
        println(t2)

        val t3 = t1.toList
        println(t3)
        val t4 = t2.toArray
        t4 foreach (l => print(l + " "))
        println("\n")

    }

    def iSort(list: List[Int]): List[Int] = {
        if (list.isEmpty)
            Nil
        else
            insertList(list.head, iSort(list.tail))
    }

    def insertList(x: Int, xs: List[Int]): List[Int] = {
        xs match {
            case List() => List(x)
            case h :: t => {
                if (x <= h) x :: xs
                else h :: insertList(x, t)
            }
        }
    }

    def printL[T](xs: List[T]) {
        println(xs)
        println("\n----\n")
    }

    def appendList[T](xs: List[T], ys: List[T]): List[T] = {
        xs match {
            case List()       => ys
            case head :: tail => head :: appendList(tail, ys)
        }
    }

    //retrieve the last element of list 
    def endElemList[T](xs: List[T]): Option[T] = {

        xs match {
            case List()       => None
            case List(x)      => Some(x)
            case head :: tail => endElemList(tail)
        }
    }

    def reverseList[T](xs: List[T]): List[T] = {
        xs match {
            case List()       => xs
            case head :: tail => reverseList(tail) ::: List(head)
        }
    }

    //(a,b,c) -- (1,2,3) -> (a,1,b,2,c,3) 
    def append1[T](xs: List[T], ys: List[T]): List[T] = {

        xs match {
            case List()  => ys
            case List(n) => xs ::: ys
            case h1 :: t1 => {
                ys match {
                    case List()  => xs
                    case List(m) => List(h1) ::: List(m) ::: t1
                    case h2 :: t2 => {
                        List(h1, h2) ::: append1(t1, t2)
                    }
                }
            }
        }
    }

    // counts the words 
    def countWords(text: String) = {

        //Note : Map in use is : scala.collection.mutable.Map 
        val counts: Map[String, Int] = Map()
        for (rawWord <- text.split("[ ,!.]+")) {
            val word = rawWord.toLowerCase
            val oldCount =
                if (counts.contains(word)) counts(word)
                else 0
            counts += (word -> (oldCount + 1))
        }
        counts
    }

    /*
    *
    * 
    */
}